package message;

import java.math.BigInteger;
import java.util.LinkedList;

import util.Point;

public class Cipher {
	
	private Point publicKey;
	private BigInteger k;
	private LinkedList<Point> encryptedPoints;
	private LinkedList<Point> signatures;
	
	/**
	 * Constructor for an unsigned cipher.
	 * @param publicKey the public key of the sender
	 * @param encryptedPoints the encrypted message points
	 */
	Cipher(Point publicKey, BigInteger k, LinkedList<Point> encryptedPoints) {
		if (encryptedPoints == null ) {
			throw new IllegalArgumentException("EncryptedPoints must not be null.");
		}
		if (encryptedPoints.size() == 0) {
			throw new IllegalArgumentException("Shared key size must be greater than zero.");
		}
		
		this.publicKey = publicKey;
		this.k = k;
		this.encryptedPoints = encryptedPoints;
		this.signatures = null;
	}
	
	/**
	 * Constructor for a signed cipher. Every encrypted point has to have a signature.
	 * @param publicKey the public key of the sender
	 * @param encryptedPoints the encrypted points
	 * @param signatures the signatures for the encrypted points
	 */
	Cipher(Point publicKey, BigInteger k, LinkedList<Point> encryptedPoints, LinkedList<Point> signatures) {
		this(publicKey, k, encryptedPoints);
		
		if (signatures == null) {
			throw new IllegalArgumentException("Signatures must not be null.");
		}
		
		if (encryptedPoints.size() != signatures.size()) {
			throw new IllegalArgumentException("Size mismatch for message points and signatures.");
		}
		
		this.signatures = signatures;
	}

	/**
	 * @return the publicKey
	 */
	public Point getPublicKey() {
		return publicKey;
	}
	
	public BigInteger getK() {
		return k;
	}

	/**
	 * @return the encryptedPoints
	 */
	LinkedList<Point> getEncryptedPoints() {
		return encryptedPoints;
	}

	/**
	 * @return the signatures
	 */
	LinkedList<Point> getSignatures() {
		return signatures;
	}
	
	/**
	 * @return true, if the message points in this cipher are signed
	 */
	public boolean isSigned() {
		return (signatures != null && signatures.size() > 0);
	}
	
	/**
	 * Adds signatures for the message points
	 * @param signatures
	 */
	void addSignatures(LinkedList<Point> signatures) {
		if (isSigned()) {
			throw new RuntimeException("Cipher is already signed.");
		}

		if (encryptedPoints.size() != signatures.size()) {
			throw new IllegalArgumentException("Size mismatch for message points and signatures.");
		}
		
		this.signatures = signatures;
	}
	
//	public String toString() {
//		String output = "[k=" + k + "; " + publicKey.toString() + "; size points=" + encryptedPoints.size();
//		output += (signatures != null) ? ("; size sigs=" + signatures.size() + ";") : ("; <null>;");
//		for (int i = 0; i < encryptedPoints.size(); i++) {
//			output += "\n" + encryptedPoints.get(i).toString();
//			if (signatures != null) {
//				output += "; " + signatures.get(i).toString();
//			}
//		}
//		output += "]";
//		return output;
//	}
	
//	public int getSize() {
//		return encryptedPoints.size();
//	}
}